package main

import (
	"database/sql"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/websocket"
)

const (
	FrameHeader = 0xA55A
	FrameTail   = 0xCC33C33C
)

var wsUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}
var wsClient *websocket.Conn

type Frame struct {
	Header       uint16
	Length       uint8
	Manufacturer uint8
	Version      uint8
	FrameType    uint8
	DeviceID     [4]byte
	Info         []byte
	Checksum     uint8
	Tail         uint32
}

type DeviceAttributes struct {
	SIMCard          string
	GroupID          uint16
	TowerInGroup     uint16
	RopeRate         uint8
	XCoordinate      float32
	YCoordinate      float32
	FrontArmLength   float32
	RearArmLength    float32
	TowerCapHeight   float32
	TowerBodyHeight  float32
	Longitude        float64
	Latitude         float64
	MaxLeftAngle     float32
	MaxRightAngle    float32
	MaxFrontDistance float32
	MaxRearDistance  float32
	MaxHeight        float32
	MaxWeight        float32
	WarningRate      uint8
	AlarmRate        uint8
	ViolationRate    uint8
	MaxTorqueLimit   float32 // 力矩限位最大值
}

type RealTimeData struct {
	Height            float32
	Amplitude         float32
	Angle             float32
	Load              float32
	SafetyLoad        float32
	Torque            float32
	Timestamp         time.Time
	WindSpeed         float32
	InclinationX      float32
	InclinationY      float32
	Status            uint32
	SafetyLoadPercent uint8
	TorqueLoadPercent uint8
	// 添加下降深度字段，假设为float32类型
	DescentDepth float32
}

type LiftingData struct {
	UploadTimestamp  time.Time
	StartTimestamp   time.Time
	EndTimestamp     time.Time
	MaxLoad          float32
	MaxLoadPercent   uint8
	MaxTorque        float32
	MaxTorquePercent uint8
	StartAngle       float32
	EndAngle         float32
	StartAmplitude   float32
	EndAmplitude     float32
	MaxAmplitude     float32
	MinAmplitude     float32
	StartHeight      float32
	EndHeight        float32
	MaxHeight        float32
	MinHeight        float32
	MaxWindSpeed     float32
	MaxInclinationX  float32
	MaxInclinationY  float32
	Status           uint32
}

// 计算校验和
func calculateChecksum(data []byte) uint8 {
	var checksum uint8
	for _, b := range data {
		checksum += b
	}
	return checksum
}

func parseTimestamp(info []byte) (time.Time, error) {
	if len(info) < 4 {
		return time.Time{}, fmt.Errorf("信息段太短，无法解析时间戳")
	}
	timestamp := binary.BigEndian.Uint32(info[:4])
	return time.Unix(int64(timestamp), 0), nil
}

func parseDeviceAttributes(info []byte) (*DeviceAttributes, error) {
	if len(info) < 88 {
		return nil, fmt.Errorf("信息段太短，无法解析设备属性")
	}

	attributes := &DeviceAttributes{
		SIMCard:          string(info[:20]),
		GroupID:          binary.BigEndian.Uint16(info[20:22]),
		TowerInGroup:     binary.BigEndian.Uint16(info[22:24]),
		RopeRate:         info[24],
		XCoordinate:      float32(binary.BigEndian.Uint32(info[25:29])) / 100,
		YCoordinate:      float32(binary.BigEndian.Uint32(info[29:33])) / 100,
		FrontArmLength:   float32(binary.BigEndian.Uint32(info[33:37])) / 100,
		RearArmLength:    float32(binary.BigEndian.Uint32(info[37:41])) / 100,
		TowerCapHeight:   float32(binary.BigEndian.Uint32(info[41:45])) / 100,
		TowerBodyHeight:  float32(binary.BigEndian.Uint32(info[45:49])) / 100,
		Longitude:        float64(binary.BigEndian.Uint32(info[49:53])) / 1000000,
		Latitude:         float64(binary.BigEndian.Uint32(info[53:57])) / 1000000,
		MaxLeftAngle:     float32(binary.BigEndian.Uint32(info[57:61])) / 100,
		MaxRightAngle:    float32(binary.BigEndian.Uint32(info[61:65])) / 100,
		MaxFrontDistance: float32(binary.BigEndian.Uint32(info[65:69])) / 100,
		MaxRearDistance:  float32(binary.BigEndian.Uint32(info[69:73])) / 100,
		MaxHeight:        float32(binary.BigEndian.Uint32(info[73:77])) / 100,
		MaxWeight:        float32(binary.BigEndian.Uint32(info[77:81])) / 100,
		WarningRate:      info[81],
		AlarmRate:        info[82],
		ViolationRate:    info[83],
		MaxTorqueLimit:   float32(binary.BigEndian.Uint32(info[84:88])) / 100,
	}

	return attributes, nil
}

func parseSignedFloat32(data []byte) float32 {
	bits := binary.BigEndian.Uint32(data)
	return float32(int32(bits)) / 100
}

// parseAngleToInt32WithTwoDecimals 将4字节的字节序列解析为有符号的32位整数，并转换为两位小数的角度值
func parseAngleToInt32WithTwoDecimals(data []byte) float32 {
	angleInt32 := int32(binary.BigEndian.Uint32(data))
	// 将角度转换为float32，并除以10的7次方来保留两位小数
	angleFloat32 := float32(angleInt32) / 100.0
	return angleFloat32
}
func parseRealTimeData(info []byte) (*RealTimeData, error) {
	if len(info) < 50 {
		return nil, fmt.Errorf("信息段太短，无法解析实时数据")
	}

	timestamp := binary.BigEndian.Uint32(info[:4]) // 上传时间戳
	data := &RealTimeData{
		Timestamp:         time.Unix(int64(timestamp), 0),                      // 时间戳转换
		Height:            float32(binary.BigEndian.Uint32(info[4:8])) / 100,   // 高度
		Amplitude:         float32(binary.BigEndian.Uint32(info[8:12])) / 100,  // 幅度
		Angle:             parseAngleToInt32WithTwoDecimals(info[12:16]),       // 转角
		Load:              float32(binary.BigEndian.Uint32(info[16:20])) / 100, // 载重
		SafetyLoad:        float32(binary.BigEndian.Uint32(info[20:24])) / 100, // 安全载重
		SafetyLoadPercent: info[24],                                            // 安全载重百分比
		Torque:            float32(binary.BigEndian.Uint32(info[25:29])) / 100, // 力矩
		TorqueLoadPercent: info[29],                                            // 力矩载重百分比
		WindSpeed:         float32(binary.BigEndian.Uint32(info[30:34])),       // 当前风速
		InclinationX:      parseAngleToInt32WithTwoDecimals(info[34:38]),       // 倾斜角度X
		InclinationY:      parseAngleToInt32WithTwoDecimals(info[38:42]),       // 倾斜角度Y
		Status:            binary.BigEndian.Uint32(info[42:46]),                // 设备状态
		DescentDepth:      float32(binary.BigEndian.Uint32(info[46:50])) / 100, // 下降深度
	}

	return data, nil
}

func parseLiftingData(info []byte) (*LiftingData, error) {
	if len(info) < 78 {
		return nil, fmt.Errorf("信息段太短，无法解析吊装数据")
	}

	uploadTimestamp := binary.BigEndian.Uint32(info[:4])
	startTimestamp := binary.BigEndian.Uint32(info[4:8])
	endTimestamp := binary.BigEndian.Uint32(info[8:12])
	data := &LiftingData{
		UploadTimestamp:  time.Unix(int64(uploadTimestamp), 0),
		StartTimestamp:   time.Unix(int64(startTimestamp), 0),
		EndTimestamp:     time.Unix(int64(endTimestamp), 0),
		MaxLoad:          float32(binary.BigEndian.Uint32(info[12:16])) / 100,
		MaxLoadPercent:   info[16],
		MaxTorque:        parseSignedFloat32(info[17:21]),
		MaxTorquePercent: info[21],
		StartAngle:       parseSignedFloat32(info[22:26]),
		EndAngle:         parseSignedFloat32(info[26:30]),
		StartAmplitude:   float32(binary.BigEndian.Uint32(info[30:34])) / 100,
		EndAmplitude:     float32(binary.BigEndian.Uint32(info[34:38])) / 100,
		MaxAmplitude:     float32(binary.BigEndian.Uint32(info[38:42])) / 100,
		MinAmplitude:     float32(binary.BigEndian.Uint32(info[42:46])) / 100,
		StartHeight:      float32(binary.BigEndian.Uint32(info[46:50])) / 100,
		EndHeight:        float32(binary.BigEndian.Uint32(info[50:54])) / 100,
		MaxHeight:        float32(binary.BigEndian.Uint32(info[54:58])) / 100,
		MinHeight:        float32(binary.BigEndian.Uint32(info[58:62])) / 100,
		MaxWindSpeed:     float32(info[62]),
		MaxInclinationX:  parseSignedFloat32(info[63:67]),
		MaxInclinationY:  parseSignedFloat32(info[67:71]),
		Status:           binary.BigEndian.Uint32(info[71:75]),
	}

	return data, nil
}

func parseFrame(data []byte) (*Frame, error) {
	if len(data) < 14 { // Minimum frame length
		return nil, fmt.Errorf("数据太短")
	}

	header := binary.BigEndian.Uint16(data[0:2])
	if header != FrameHeader {
		return nil,
			fmt.Errorf("无效的帧头: %x", header)
	}

	length := data[2]
	expectedLength := int(length) // Length includes the entire frame length
	if len(data) != expectedLength {
		return nil, fmt.Errorf("无效的数据长度: 期望 %d, 实际 %d", expectedLength, len(data))
	}

	tail := binary.BigEndian.Uint32(data[len(data)-4:])
	if tail != FrameTail {
		return nil, fmt.Errorf("无效的帧尾: %x", tail)
	}

	frame := &Frame{
		Header:       header,
		Length:       length,
		Manufacturer: data[3],
		Version:      data[4],
		FrameType:    data[5],
	}
	copy(frame.DeviceID[:], data[6:10])
	frame.Info = data[10 : len(data)-5]
	frame.Checksum = data[len(data)-5]
	frame.Tail = tail

	// 计算校验和并验证
	calculatedChecksum := calculateChecksum(data[:len(data)-5])
	if calculatedChecksum != frame.Checksum {
		return nil, fmt.Errorf("校验和错误: 期望 %x, 实际 %x", calculatedChecksum, frame.Checksum)
	}

	return frame, nil
}

func handleClient(conn net.Conn, db *sql.DB) {
	defer conn.Close()

	buffer := make([]byte, 0)
	tempBuffer := make([]byte, 1024)

	for {
		n, err := conn.Read(tempBuffer)
		if err != nil {
			log.Println("读取数据失败:", err)
			break
		}

		buffer = append(buffer, tempBuffer[:n]...)

		for len(buffer) >= 14 {
			header := binary.BigEndian.Uint16(buffer[0:2])
			if header != FrameHeader {
				log.Println("无效的帧头:", header)
				buffer = buffer[1:]
				continue
			}

			length := buffer[2]
			expectedLength := int(length)
			if len(buffer) < expectedLength {
				break
			}

			frameData := buffer[:expectedLength]
			buffer = buffer[expectedLength:]

			frame, err := parseFrame(frameData)
			if err != nil {
				log.Println("解析数据失败:", err)
				continue
			}

			fmt.Printf("帧头: 0x%x\n", frame.Header)
			fmt.Printf("长度: %d\n", frame.Length)
			fmt.Printf("厂家编号: 0x%x\n", frame.Manufacturer)
			fmt.Printf("协议版本: 0x%x\n", frame.Version)
			fmt.Printf("帧类型: 0x%x\n", frame.FrameType)
			fmt.Printf("设备编号: %x\n", frame.DeviceID)
			fmt.Printf("帧尾: 0x%x\n", frame.Tail)

			// 将 DeviceID 转换为 []byte
			deviceID := frame.DeviceID[:]

			// 根据帧类型处理数据
			switch frame.FrameType {
			case 0x00: // 设备注册请求帧
				type t struct {
					DeviceID  [4]byte   `json:"device_id"`
					Timestamp time.Time `json:"timestamp"`
				}
				var reg t
				timestamp, err := parseTimestamp(frame.Info)
				if err != nil {
					log.Println("解析时间戳失败:", err)
					continue
				}
				reg.Timestamp = timestamp
				copy(reg.DeviceID[:], frame.DeviceID[:])
				fmt.Printf("解析的时间戳: %s\n", reg.Timestamp.Format(time.RFC3339))
				// 插入数据库
				_, err = db.Exec("INSERT INTO device_registration (device_id, timestamp) VALUES (?, ?)", deviceID, timestamp)
				if err != nil {
					log.Println("插入设备注册数据失败:", err)

				}
				err = writeToWebSocket(reg)
				if err != nil {
					log.Println("发送数据到WebSocket服务器失败:", err)
				} else {
					log.Println("注册信息成功发送到WebSocket服务器")
				}
			case 0x02: // 设备参数上报请求帧
				attributes, err := parseDeviceAttributes(frame.Info)
				if err != nil {
					log.Println("解析设备属性信息失败:", err)
					continue
				}
				// 打印设备属性信息
				fmt.Printf("SIM卡号: %s\n", attributes.SIMCard)
				fmt.Printf("群塔ID: %d\n", attributes.GroupID)
				fmt.Printf("塔机在群: %d\n", attributes.TowerInGroup)
				fmt.Printf("吊绳倍率: %d\n", attributes.RopeRate)
				fmt.Printf("X坐标: %.2f\n", attributes.XCoordinate)
				fmt.Printf("Y坐标: %.2f\n", attributes.YCoordinate)
				fmt.Printf("前臂长度: %.2f\n", attributes.FrontArmLength)
				fmt.Printf("后臂长度: %.2f\n", attributes.RearArmLength)
				fmt.Printf("塔帽高度: %.2f\n", attributes.TowerCapHeight)
				fmt.Printf("塔身高度: %.2f\n", attributes.TowerBodyHeight)
				fmt.Printf("经度: %.6f\n", attributes.Longitude)
				fmt.Printf("纬度: %.6f\n", attributes.Latitude)
				fmt.Printf("前行最远距离: %.2f\n", attributes.MaxFrontDistance)
				fmt.Printf("回收最近距离: %.2f\n", attributes.MaxRearDistance)
				fmt.Printf("最高高度: %.2f\n", attributes.MaxHeight)
				fmt.Printf("最大起重量: %.2f\n", attributes.MaxWeight)
				fmt.Printf("预警百分比: %d\n", attributes.WarningRate)
				fmt.Printf("报警百分比: %d\n", attributes.AlarmRate)
				fmt.Printf("违章百分比: %d\n", attributes.ViolationRate)
				fmt.Printf("力矩限位最大值: %.2f\n", attributes.MaxTorqueLimit)
				// 插入数据库
				_, err = db.Exec(`INSERT INTO device_attributes (sim_card, group_id, tower_in_group, rope_rate, x_coordinate, y_coordinate, front_arm_length, rear_arm_length, tower_cap_height, tower_body_height, longitude, latitude, max_left_angle, max_right_angle, max_front_distance, max_rear_distance, max_height, max_weight, warning_rate, alarm_rate, violation_rate, max_torque_limit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
					attributes.SIMCard, attributes.GroupID, attributes.TowerInGroup, attributes.RopeRate, attributes.XCoordinate, attributes.YCoordinate, attributes.FrontArmLength, attributes.RearArmLength, attributes.TowerCapHeight, attributes.TowerBodyHeight, attributes.Longitude, attributes.Latitude, attributes.MaxLeftAngle, attributes.MaxRightAngle, attributes.MaxFrontDistance, attributes.MaxRearDistance, attributes.MaxHeight, attributes.MaxWeight, attributes.WarningRate, attributes.AlarmRate, attributes.ViolationRate, attributes.MaxTorqueLimit)
				if err != nil {
					log.Println("插入设备属性数据失败:", err)
				}
				err = writeToWebSocket(attributes)
				if err != nil {
					log.Println("发送数据到WebSocket服务器失败:", err)
				} else {
					log.Println("设备属性数据发送到WebSocket服务器")

				}
			case 0x06: // 设备实时数据上传请求帧
				realTimeData, err := parseRealTimeData(frame.Info)
				if err != nil {
					log.Println("解析实时数据失败:", err)
					continue
				}
				// 打印实时数据
				fmt.Printf("高度: %.2f\n", realTimeData.Height)
				fmt.Printf("幅度: %.2f\n", realTimeData.Amplitude)
				fmt.Printf("转角: %.2f\n", realTimeData.Angle)
				fmt.Printf("载重: %.2f\n", realTimeData.Load)
				fmt.Printf("安全载重: %.2f\n", realTimeData.SafetyLoad)
				fmt.Printf("力矩: %.2f\n", realTimeData.Torque)
				fmt.Printf("时间戳: %s\n", realTimeData.Timestamp.Format(time.RFC3339))
				fmt.Printf("风速: %.2f\n", realTimeData.WindSpeed)
				fmt.Printf("安全载重百分比: %d\n", realTimeData.SafetyLoadPercent)
				fmt.Printf("力矩载重百分比: %d\n", realTimeData.TorqueLoadPercent)
				fmt.Printf("倾斜角度X: %.2f\n", realTimeData.InclinationX)
				fmt.Printf("倾斜角度Y: %.2f\n", realTimeData.InclinationY)
				fmt.Printf("设备状态: %032b\n", realTimeData.Status)
				// 添加打印下降深度字段
				fmt.Printf("下降深度: %.2f\n", realTimeData.DescentDepth)
				// 插入数据库
				// 假定 handleClient 中已经定义了 realTimeData 变量
				// 并且已经调用 parseRealTimeData 函数填充了 realTimeData 的字段
				_, err = db.Exec(`INSERT INTO real_time_data 
                (height, amplitude, angle, load1, safety_load, safety_load_percent, torque, torque_load_percent, wind_speed, inclination_x, inclination_y, status, descent_depth, timestamp) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
					realTimeData.Height, realTimeData.Amplitude, realTimeData.Angle, realTimeData.Load,
					realTimeData.SafetyLoad, realTimeData.SafetyLoadPercent, realTimeData.Torque, realTimeData.TorqueLoadPercent,
					realTimeData.WindSpeed, realTimeData.InclinationX, realTimeData.InclinationY, realTimeData.Status,
					realTimeData.DescentDepth, realTimeData.Timestamp)
				err = writeToWebSocket(realTimeData)
				if err != nil {
					log.Println("发送数据到WebSocket服务器失败:", err)
				} else {
					log.Println("实时数据成功发送到WebSocket服务器")
				}
			case 0x08: // 吊装数据上传请求帧
				liftingData, err := parseLiftingData(frame.Info)
				if err != nil {
					log.Println("解析吊装数据失败:", err)
					continue
				}
				// 打印吊装数据
				fmt.Printf("上传时间戳: %s\n", liftingData.UploadTimestamp.Format(time.RFC3339))
				fmt.Printf("开始时间戳: %s\n", liftingData.StartTimestamp.Format(time.RFC3339))
				fmt.Printf("结束时间戳: %s\n", liftingData.EndTimestamp.Format(time.RFC3339))
				fmt.Printf("最大载重: %.2f\n", liftingData.MaxLoad)
				fmt.Printf("最大载重百分比: %d\n", liftingData.MaxLoadPercent)
				fmt.Printf("最大力矩: %.2f\n", liftingData.MaxTorque)
				fmt.Printf("最大力矩百分比: %d\n", liftingData.MaxTorquePercent)
				fmt.Printf("开始转角: %.2f\n", liftingData.StartAngle)
				fmt.Printf("结束转角: %.2f\n", liftingData.EndAngle)
				fmt.Printf("开始幅度: %.2f\n", liftingData.StartAmplitude)
				fmt.Printf("结束幅度: %.2f\n", liftingData.EndAmplitude)
				fmt.Printf("最大工作幅度: %.2f\n", liftingData.MaxAmplitude)
				fmt.Printf("最小工作幅度: %.2f\n", liftingData.MinAmplitude)
				fmt.Printf("开始起升高度: %.2f\n", liftingData.StartHeight)
				fmt.Printf("结束起升高度: %.2f\n", liftingData.EndHeight)
				fmt.Printf("最大起升高度: %.2f\n", liftingData.MaxHeight)
				fmt.Printf("最小起升高度: %.2f\n", liftingData.MinHeight)
				fmt.Printf("最大风速: %.2f\n", liftingData.MaxWindSpeed)
				fmt.Printf("最大倾角X: %.2f\n", liftingData.MaxInclinationX)
				fmt.Printf("最大倾角Y: %.2f\n", liftingData.MaxInclinationY)
				fmt.Printf("设备状态: %032b\n", liftingData.Status)
				// 插入数据库
				_, err = db.Exec(`INSERT INTO lifting_data (upload_timestamp, start_timestamp, end_timestamp, max_load, max_load_percent, max_torque, max_torque_percent, start_angle, end_angle, start_amplitude, end_amplitude, max_amplitude, min_amplitude, start_height, end_height, max_height, min_height, max_wind_speed, max_inclination_x, max_inclination_y, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
					liftingData.UploadTimestamp, liftingData.StartTimestamp, liftingData.EndTimestamp, liftingData.MaxLoad, liftingData.MaxLoadPercent, liftingData.MaxTorque, liftingData.MaxTorquePercent, liftingData.StartAngle, liftingData.EndAngle, liftingData.StartAmplitude, liftingData.EndAmplitude, liftingData.MaxAmplitude, liftingData.MinAmplitude, liftingData.StartHeight, liftingData.EndHeight, liftingData.MaxHeight, liftingData.MinHeight, liftingData.MaxWindSpeed, liftingData.MaxInclinationX, liftingData.MaxInclinationY, liftingData.Status)
				if err != nil {
					log.Println("插入吊装数据失败:", err)
				}
				err = writeToWebSocket(liftingData)
				if err != nil {
					log.Println("发送数据到WebSocket服务器失败:", err)
				} else {
					log.Println("吊装数据成功发送到WebSocket服务器")
				}
			default:
				fmt.Println("未知帧类型:", frame.FrameType)
			}

			// 将接收到的数据发送回客户端
			_, err = conn.Write(frameData)
			if err != nil {
				log.Println("发送数据失败:", err)
				break
			}
		}
	}
}

func writeToWebSocket(v interface{}) error {
	// 序列化数据为JSON格式的[]byte
	data, err := json.Marshal(v)
	if err != nil {
		return err
	}
	// 发送数据到WebSocket服务器
	return wsClient.WriteMessage(websocket.TextMessage, data)
}
func main() {
	// 数据库连接配置
	dsn := "root:cx2002114@tcp(127.0.0.1:3306)/db2"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal("数据库连接失败:", err)
	}
	defer db.Close()

	// 测试数据库连接
	err = db.Ping()
	if err != nil {
		log.Fatal("数据库连接测试失败:", err)
	}
	initWebSocket("ws://192.168.43.179:8081/ws")
	listener, err := net.Listen("tcp", ":5050")
	if err != nil {
		log.Fatal("监听失败:", err)
	}
	defer listener.Close()

	fmt.Println("服务器启动，监听 5050 端口...")

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println("接受连接失败:", err)
			continue
		}

		go handleClient(conn, db)
	}
}
func initWebSocket(url string) {
	// 这里使用gorilla/websocket提供的Dialer来建立连接
	var err error
	wsClient, _, err = websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		log.Fatal("无法连接到WebSocket服务器:", err)
	}
}
